package com.feature.learn.jvm;

import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import groovy.util.logging.Slf4j;

import java.lang.management.*;
import java.util.List;

/**
 * 堆分配参数
 * 设置-Xmx 和 -Xms 来修改默认的最大堆与初始化堆
 * <p>
 * maxMemory:3641M
 * freeMemory:1932M
 * totalMemory:1963M
 * totalMemory 就是初始化堆大小，它的意思是一开始限定堆大小为多少，如果不够则可以扩充，但必须小于最大堆大小。
 */
@Slf4j
public class TestMaxMinHeap {

    private static final int M = 1024 * 1024;

    public static void main(String[] args) {
        /**
         *   maxMemory:18M
         *	 freeMemory:4M
         *	 totalMemory:5M
         *	 因为b[]变为
         *	 maxMemory:18M
         *	 freeMemory:2M
         *	 totalMemory:5M
         *
         *	 消耗2M
         */
        byte b[] = new byte[11 * M];
//		byte b[] = new byte[6 * M];
        // Java heap space
//		byte b[] = new byte[21 * M];


        System.out.println("maxMemory:" + (Runtime.getRuntime().maxMemory() / 1024 / 1024) + "M");
        System.out.println("freeMemory:" + (Runtime.getRuntime().freeMemory() / 1024 / 1024) + "M");
        System.out.println("totalMemory:" + (Runtime.getRuntime().totalMemory() / 1024 / 1024) + "M");

        // -Xms6m -Xmx6m

        /**
         * Init：java虚拟机在启动的时候向操作系统请求的初始内存容量，java虚拟机在运行的过程中可能向操作系统请求更多的内存或将内存释放给操作系统，
         * 所以init的值是不确定的。
         * Used：当前已经使用的内存量。
         * Committed：表示保证java虚拟机能使用的内存量，已提交的内存量可以随时间而变化（增加或减少）。Java 虚拟机可能会将内存释放给系统，
         * committed 可以小于 init。committed 将始终大于或等于 used。
         * Max：表示可以用于内存管理的最大内存量（以字节为单位）。可以不定义其值。如果定义了该值，最大内存量可能随时间而更改。
         * 已使用的内存量和已提 交的内存量将始终小于或等于 max（如果定义了 max）。如果内存分配试图增加满足以下条件的已使用内存将会失败：
         * used > committed，即使 used <= max 仍然为 true（例如，当系统的虚拟内存不足时）。
         */
        // 获取MemoryMXBean
        MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
        // 打印：堆内存使用
        System.out.println(("heapMemoryUsage: {}" + memoryMXBean.getHeapMemoryUsage().toString()));
        // 打印：非堆内存使用
        System.out.println(("nonHeapMemoryUsage: {}" + memoryMXBean.getNonHeapMemoryUsage().toString()));
		System.out.println("========================================================================================");
        // 获取所有内存管理器MXBean列表，并遍历
        List<MemoryManagerMXBean> memoryManagerMXBeans = ManagementFactory.getMemoryManagerMXBeans();

        for (MemoryManagerMXBean memoryManagerMXBean : memoryManagerMXBeans) {
            // 获取管理器名称
            String name = memoryManagerMXBean.getName();
            // 获取此内存管理器管理的内存池名称
            String[] memoryPoolNames = memoryManagerMXBean.getMemoryPoolNames();

            System.out.println("memoryManagerName: {}" + name + ", memoryPoolNames: {}" + JSONUtil.toJsonStr(memoryPoolNames));
        }
		System.out.println("========================================================================================");
        // 获取所有内存池MXBean列表，并遍历
        List<MemoryPoolMXBean> memoryPoolMXBeans = ManagementFactory.getMemoryPoolMXBeans();
        for (MemoryPoolMXBean memoryPoolMXBean : memoryPoolMXBeans) {
            // 内存分区名
            String name = memoryPoolMXBean.getName();
            // 内存管理器名称
            String[] memoryManagerNames = memoryPoolMXBean.getMemoryManagerNames();
            // 内存分区类型
            MemoryType type = memoryPoolMXBean.getType();
            // 内存使用情况
            MemoryUsage usage = memoryPoolMXBean.getUsage();
            // 内存使用峰值情况
            MemoryUsage peakUsage = memoryPoolMXBean.getPeakUsage();
            // 打印
            System.out.println(name + ":");
            System.out.println("    managers: " + JSONUtil.toJsonStr(memoryManagerNames));
            System.out.println("    type: " + type.toString());
            System.out.println("    usage: " + usage.toString());
            System.out.println("    peakUsage: " + peakUsage.toString());
            System.out.println("");
        }
    }
}